package simpledb.algorithm.join;

import simpledb.execution.JoinPredicate;
import simpledb.execution.OpIterator;
import simpledb.storage.Tuple;
import simpledb.storage.TupleDesc;
import simpledb.storage.TupleIterator;

import java.util.Arrays;

/**
 * JoinStrategy 是所有连接策略的抽象基类。
 * 它定义了连接两个关系的基本接口，并提供了通用的辅助方法。
 */
public abstract class JoinStrategy {

    // 左侧输入源（外层表）
    protected final OpIterator    child1;

    // 右侧输入源（内层表）
    protected final OpIterator    child2;

    // 输出元组的描述信息
    protected final TupleDesc     td;

    // 连接谓词条件
    protected final JoinPredicate joinPredicate;

    /**
     * 构造函数：创建一个连接策略。
     *
     * @param child1 左边表的输入流（外层循环）
     * @param child2 右边表的输入流（内层循环）
     * @param td 合并后的输出结构（child1 + child2）
     * @param joinPredicate 连接条件谓词
     */
    public JoinStrategy(final OpIterator child1, final OpIterator child2, final TupleDesc td,
                        final JoinPredicate joinPredicate) {
        this.child1 = child1;
        this.child2 = child2;
        this.td = td;
        this.joinPredicate = joinPredicate;
    }

    /**
     * 将两个元组合并为一个新的元组。
     * 通常用于将左右两边的元组拼接成连接结果。
     *
     * @param tuple1 左侧元组
     * @param tuple2 右侧元组
     * @param td 合并后的元组描述
     * @return 拼接后的新元组
     */
    protected Tuple mergeTuple(final Tuple tuple1, final Tuple tuple2, final TupleDesc td) {
        final Tuple tuple = new Tuple(td);
        int len1 = tuple1.getTupleDesc().numFields();

        // 复制左侧元组字段
        for (int i = 0; i < len1; i++) {
            tuple.setField(i, tuple1.getField(i));
        }

        // 复制右侧元组字段，从左侧之后开始放置
        for (int i = 0; i < tuple2.getTupleDesc().numFields(); i++) {
            tuple.setField(i + len1, tuple2.getField(i));
        }

        return tuple;
    }

    /**
     * 从指定的子操作符中读取一批元组到数组中。
     *
     * @param child 输入源
     * @param tuples 存储读取结果的数组
     * @return 实际读取的元组数量
     * @throws Exception
     */
    protected int fetchTuples(final OpIterator child, final Tuple[] tuples) throws Exception {
        int i = 0;
        Arrays.fill(tuples, null); // 初始化数组内容为 null

        while (child.hasNext() && i < tuples.length) {
            final Tuple next = child.next();
            if (next != null) {
                tuples[i++] = next;
            }
        }

        return i;
    }

    /**
     * 执行连接操作，返回包含连接结果的迭代器。
     *
     * @return 包含连接结果的 TupleIterator
     */
    public abstract TupleIterator doJoin();

    /**
     * 关闭该连接策略及其资源。
     */
    public abstract void close();
}
